-- 2022-8-12

---[[预编译的代码

    -- 正如笔者在本章开头所提到的 Lua语言会在运行源代码之前先对其进行预编译 Lua语言也允许我们以预编译的形式分发代码
    -- 生成预编译文件(也被称为二进制文件 binary chunk)的最简单的方式是 使用标准发行版中附带的luac程序
    -- 例如 下列命令会创建文件prog.lua的预编译版本prog.lc
    -- $ luac -o prog.lc prog.lua
    -- Lua解析器会像执行普通Lua代码一样执行这个新文件 完成与原来代码完全一致的动作
    -- $ lua prog.lc
    -- 几乎在Lua语言中所有能够使用源码的地方都可以使用预编译代码 特别的 函数loadfile和函数load都可以接收预编译代码
    -- 我们可以直接在Lua语言中实现一个最简单的luac
    p = loadfile(arg[1])
    f = io.open(arg[2],"wb")
    f:write(string.dump(p))
    f:close()
    -- 这里的关键函数是string.dump 该函数的入参是一个Lua函数 返回值是传入函数对于的字符串形式的预编译代码(已被正确的格式化 可由Lua语言直接加载)
    -- luac程序提供了一些有意思的选项 特别的 选项-l会列出编译器为指定代码段生成的操作码(opcode)
    -- 例如 示例16.1展示了函数luac针对如下只有一行内容的文件在带有-l选项时的输出
    -- a = x + y - z

    -- 示例16.1 luac -l 的输出示例
    -- 省略

    -- (我们不会在本书中讨论Lua语言的内部细节 如果读者对这些操作嘛的更多信息感兴趣 可以在网上搜索"lua opcode"来获得相关资料)

    -- 预编译形式的代码不一定比源代码更小 但是却加载的更快 预编译形式的代码的另一个好处是 可以避免由于意外而修改源码
    -- 然而 与源代码不同 蓄意损坏或构造的二进制代码可能会让Lua解析器崩溃或甚至执行用户提供的机器码
    -- 当运行一般的代码时通常无须担心 但应该避免运行以预编译形式给出的非受信代码 这种需求 函数load正好有一个选项可以适用

    -- 除了必需的第一个参数外 函数load还有三个可选的参数
    -- 第二个参数是程序员的名称 只在错误信息中被用到 第四个参数是环境 我们会在第22章中对其讨论
    -- 第三个参数正是我们这里所关心的 它控制了允许加载的代码段的类型
    -- 如果该参数存在 只能是如下的字符串:字符串t允许加载文本(普通)类型的代码段 字符串"b"只允许加载二进制(预编译)类型的代码段
    -- 字符串"bt"允许同时加载上述两种类型的代码段(默认情况)
--]]